﻿using KAKA.Domain;
using KAKA.Repository;
using Morus;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Threading;

namespace KAKA.Infrastructure
{
    public class EmailSender : IEmailSender
    {
        private readonly string _templateDirectory;
        private readonly bool _enableSSL;
        private readonly string _host;
        private readonly int _port;
        private readonly string _username;
        private readonly string _password;
        private readonly ISettingRepository _settings;

        private readonly string _template_Registration = "Registration";
        private readonly string _template_EmailVerification = "EmailVerification";

        public EmailSender(string host, int port, string username, string password, bool enableSSL, string templateDirectory, ISettingRepository settingRepository)
        {
            _host = host;
            _port = port;
            _username = username;
            _password = password;
            _enableSSL = enableSSL;
            _templateDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, templateDirectory);
            _settings = settingRepository;
        }

        public void SendRegistration(string email, string nickname, string token)
        {
            string body = PrepareMailBody(_template_Registration, "Nickname", nickname, "Email", email, "TokenUrl", TokenHelper.GetEmailVerificationTokenUrl(token));

            SendMailAsync(_settings.GetByName(Setting.NAME_EMAIL_ADDRESS).Value, email, Resources.Message_6000_Welcome.FormatWith(_settings.GetByName(Setting.NAME_SITE_TITLE).Value), body);
        }

        public void SendEmailVerification(string email, string nickname, string token)
        {
            string body = PrepareMailBody(_template_EmailVerification, "Nickname", nickname, "Email", email, "TokenUrl", TokenHelper.GetEmailVerificationTokenUrl(token));

            SendMailAsync(_settings.GetByName(Setting.NAME_EMAIL_ADDRESS).Value, email, Resources.Message_6000_Welcome.FormatWith(_settings.GetByName(Setting.NAME_SITE_TITLE).Value), body);
        }

        public void SendNewPassword(string email, string nickname, string token)
        {
            throw new NotImplementedException();
        }



        private string PrepareMailBody(string templateName, params string[] pairs)
        {
            string body = GetMailBodyOfTemplate(templateName);

            for (var i = 0; i < pairs.Length; i += 2)
            {
                body = body.Replace("##[{0}]##".FormatWith(pairs[i]), pairs[i + 1]);
            }

            body = body.Replace("##[SiteTitle]##", _settings.GetByName(Setting.NAME_SITE_TITLE).Value);
            body = body.Replace("##[RootUrl]##", _settings.GetByName(Setting.NAME_ROOT_URL).Value);

            return body;
        }

        private string GetMailBodyOfTemplate(string templateName)
        {
            var cacheKey = "mailTemplate:{0}".FormatWith(templateName);
            string body;

            Cache.TryGet(cacheKey, out body);

            if (string.IsNullOrEmpty(body))
            {
                body = ReadFileFrom(templateName);

                if ((!string.IsNullOrEmpty(body)) && (!Cache.Contains(cacheKey)))
                {
                    Cache.Set(cacheKey, body);
                }
            }

            return body;
        }

        private string ReadFileFrom(string templateName)
        {
            string filePath = string.Concat(Path.Combine(_templateDirectory, templateName), ".txt");

            string body = File.ReadAllText(filePath);

            return body;
        }

        private void SendMail(string fromAddress, string toAddress, string subject, string body)
        {
            using (MailMessage mail = BuildMessageWith(fromAddress, toAddress, subject, body))
            {
                SendMail(mail);
            }
        }

        private void SendMail(MailMessage mail)
        {
            try
            {
                using (SmtpClient smtp = new SmtpClient()
                {
                    EnableSsl = _enableSSL,
                    Host = _host,
                    Port = _port,
                    Credentials = new NetworkCredential(_username, _password),
                    DeliveryMethod = SmtpDeliveryMethod.Network,
                })
                {
                    smtp.Send(mail);
                };
            }
            catch (Exception e)
            {
                Log.Exception(e);
            }
        }

        private void SendMailAsync(string fromAddress, string toAddress, string subject, string body)
        {
            ThreadPool.QueueUserWorkItem(state => SendMail(fromAddress, toAddress, subject, body));
        }

        private MailMessage BuildMessageWith(string fromAddress, string toAddress, string subject, string body)
        {
            MailMessage message = new MailMessage
            {
                Sender = new MailAddress(fromAddress, _settings.GetByName(Setting.NAME_SITE_TITLE).Value),
                From = new MailAddress(fromAddress, _settings.GetByName(Setting.NAME_SITE_TITLE).Value),
                Subject = subject,
                SubjectEncoding = Encoding.UTF8,
                Body = body,
                BodyEncoding = Encoding.UTF8,
                IsBodyHtml = true,
            };

            string[] tos = toAddress.Split(';');

            foreach (string to in tos)
            {
                message.To.Add(new MailAddress(to));
            }

            return message;
        }
    }
}
